{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implementation of WGAN-GP\n",
    "Reference: https://arxiv.org/pdf/1704.00028.pdf\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Run the comment below only when using Google Colab\n",
    "# !pip install torch torchvision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.autograd as autograd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from torch.utils.data import DataLoader\n",
    "from torchvision import datasets\n",
    "from torchvision import transforms\n",
    "from torchvision.utils import save_image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import datetime\n",
    "import os, sys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from matplotlib.pyplot import imshow, imsave\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "MODEL_NAME = 'WGAN-gp'\n",
    "DEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def to_onehot(x, num_classes=10):\n",
    "    assert isinstance(x, int) or isinstance(x, (torch.LongTensor, torch.cuda.LongTensor))\n",
    "    if isinstance(x, int):\n",
    "        c = torch.zeros(1, num_classes).long()\n",
    "        c[0][x] = 1\n",
    "    else:\n",
    "        x = x.cpu()\n",
    "        c = torch.LongTensor(x.size(0), num_classes)\n",
    "        c.zero_()\n",
    "        c.scatter_(1, x, 1) # dim, index, src value\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def get_sample_image(G, n_noise=100):\n",
    "    \"\"\"\n",
    "        save sample 100 images\n",
    "    \"\"\"\n",
    "    img = np.zeros([280, 280])\n",
    "    for j in range(10):\n",
    "        c = torch.zeros([10, 10]).to(DEVICE)\n",
    "        c[:, j] = 1\n",
    "        z = torch.randn(10, n_noise).to(DEVICE)\n",
    "        y_hat = G(z,c).view(10, 28, 28)\n",
    "        result = y_hat.cpu().data.numpy()\n",
    "        img[j*28:(j+1)*28] = np.concatenate([x for x in result], axis=-1)\n",
    "    return img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Discriminator(nn.Module):\n",
    "    \"\"\"\n",
    "        Convolutional Discriminator for MNIST\n",
    "    \"\"\"\n",
    "    def __init__(self, in_channel=1, input_size=784, condition_size=10, num_classes=1):\n",
    "        super(Discriminator, self).__init__()\n",
    "        self.transform = nn.Sequential(\n",
    "            nn.Linear(input_size+condition_size, 784),\n",
    "            nn.LeakyReLU(0.2),\n",
    "        )\n",
    "        self.conv = nn.Sequential(\n",
    "            # 28 -> 14\n",
    "            nn.Conv2d(in_channel, 512, 3, stride=2, padding=1, bias=False),\n",
    "#             nn.BatchNorm2d(512),\n",
    "            nn.LeakyReLU(0.2),\n",
    "            # 14 -> 7\n",
    "            nn.Conv2d(512, 256, 3, stride=2, padding=1, bias=False),\n",
    "#             nn.BatchNorm2d(256),\n",
    "            nn.LeakyReLU(0.2),\n",
    "            # 7 -> 4\n",
    "            nn.Conv2d(256, 128, 3, stride=2, padding=1, bias=False),\n",
    "#             nn.BatchNorm2d(128),\n",
    "            nn.LeakyReLU(0.2),\n",
    "            nn.AvgPool2d(4),\n",
    "        )\n",
    "        self.fc = nn.Sequential(\n",
    "            # reshape input, 128 -> 1\n",
    "            nn.Linear(128, 1),\n",
    "        )\n",
    "    \n",
    "    def forward(self, x, c=None):\n",
    "        # x: (N, 1, 28, 28), c: (N, 10)\n",
    "        x, c = x.view(x.size(0), -1), c.float() # may not need\n",
    "        v = torch.cat((x, c), 1) # v: (N, 794)\n",
    "        y_ = self.transform(v) # (N, 784)\n",
    "        y_ = y_.view(y_.shape[0], 1, 28, 28) # (N, 1, 28, 28)\n",
    "        y_ = self.conv(y_)\n",
    "        y_ = y_.view(y_.size(0), -1)\n",
    "        y_ = self.fc(y_)\n",
    "        return y_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Generator(nn.Module):\n",
    "    \"\"\"\n",
    "        Convolutional Generator for MNIST\n",
    "    \"\"\"\n",
    "    def __init__(self, input_size=100, condition_size=10):\n",
    "        super(Generator, self).__init__()\n",
    "        self.fc = nn.Sequential(\n",
    "            nn.Linear(input_size+condition_size, 4*4*512),\n",
    "            nn.ReLU(),\n",
    "        )\n",
    "        self.conv = nn.Sequential(\n",
    "            # input: 4 by 4, output: 7 by 7\n",
    "            nn.ConvTranspose2d(512, 256, 3, stride=2, padding=1, bias=False),\n",
    "#             nn.BatchNorm2d(256),\n",
    "            nn.ReLU(),\n",
    "            # input: 7 by 7, output: 14 by 14\n",
    "            nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1, bias=False),\n",
    "#             nn.BatchNorm2d(128),\n",
    "            nn.ReLU(),\n",
    "            # input: 14 by 14, output: 28 by 28\n",
    "            nn.ConvTranspose2d(128, 1, 4, stride=2, padding=1, bias=False),\n",
    "            nn.Tanh(),\n",
    "        )\n",
    "        \n",
    "    def forward(self, x, c):\n",
    "        # x: (N, 100), c: (N, 10)\n",
    "        x, c = x.view(x.size(0), -1), c.float() # may not need\n",
    "        v = torch.cat((x, c), 1) # v: (N, 110)\n",
    "        y_ = self.fc(v)\n",
    "        y_ = y_.view(y_.size(0), 512, 4, 4)\n",
    "        y_ = self.conv(y_) # (N, 28, 28)\n",
    "        return y_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "D = Discriminator().to(DEVICE)\n",
    "G = Generator().to(DEVICE)\n",
    "# D.load_state_dict('D_dc.pkl')\n",
    "# G.load_state_dict('G_dc.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "transform = transforms.Compose([transforms.ToTensor(),\n",
    "                                transforms.Normalize(mean=[0.5],\n",
    "                                std=[0.5])]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "mnist = datasets.MNIST(root='../data/', train=True, transform=transform, download=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "batch_size = 64"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "data_loader = DataLoader(dataset=mnist, batch_size=batch_size, shuffle=True, drop_last=True, pin_memory=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "D_opt = torch.optim.Adam(D.parameters(), lr=0.0001, betas=(0., 0.9))\n",
    "G_opt = torch.optim.Adam(G.parameters(), lr=0.0001, betas=(0., 0.9))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "max_epoch = 50 # need more than 20 epochs for training generator\n",
    "step = 0\n",
    "n_noise = 100\n",
    "p_coeff = 10 # lambda\n",
    "n_critic = 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "D_labels = torch.ones([batch_size, 1]).to(DEVICE) # Discriminator Label to real\n",
    "D_fakes = torch.zeros([batch_size, 1]).to(DEVICE) # Discriminator Label to fake"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "if not os.path.exists('samples'):\n",
    "    os.makedirs('samples')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 0/50, Step: 0, D Loss: 9.836451530456543, G Loss: 0.04542214423418045\n",
      "Epoch: 0/50, Step: 500, D Loss: -17.222110748291016, G Loss: -2.790493965148926\n",
      "Epoch: 1/50, Step: 1000, D Loss: -14.437170028686523, G Loss: -4.63651704788208\n",
      "Epoch: 1/50, Step: 1500, D Loss: -12.898039817810059, G Loss: -5.126628875732422\n",
      "Epoch: 2/50, Step: 2000, D Loss: -9.202461242675781, G Loss: -7.752415657043457\n",
      "Epoch: 2/50, Step: 2500, D Loss: -3.2002816200256348, G Loss: -5.566987037658691\n",
      "Epoch: 3/50, Step: 3000, D Loss: -4.7195658683776855, G Loss: 0.524418830871582\n",
      "Epoch: 3/50, Step: 3500, D Loss: -5.08551025390625, G Loss: -1.7403905391693115\n",
      "Epoch: 4/50, Step: 4000, D Loss: -5.654188632965088, G Loss: 3.4006834030151367\n",
      "Epoch: 4/50, Step: 4500, D Loss: -6.172457695007324, G Loss: 2.4051449298858643\n",
      "Epoch: 5/50, Step: 5000, D Loss: -5.57381534576416, G Loss: -0.9589190483093262\n",
      "Epoch: 5/50, Step: 5500, D Loss: -5.090154647827148, G Loss: -5.0453643798828125\n",
      "Epoch: 6/50, Step: 6000, D Loss: -4.748830318450928, G Loss: -5.255766868591309\n",
      "Epoch: 6/50, Step: 6500, D Loss: -4.954983711242676, G Loss: -9.1829833984375\n",
      "Epoch: 7/50, Step: 7000, D Loss: -4.017940998077393, G Loss: -8.38479232788086\n",
      "Epoch: 8/50, Step: 7500, D Loss: -3.8713948726654053, G Loss: -4.522911071777344\n",
      "Epoch: 8/50, Step: 8000, D Loss: -3.0255002975463867, G Loss: -4.620765209197998\n",
      "Epoch: 9/50, Step: 8500, D Loss: -3.824171781539917, G Loss: -7.278886318206787\n",
      "Epoch: 9/50, Step: 9000, D Loss: -3.646456241607666, G Loss: -8.577272415161133\n",
      "Epoch: 10/50, Step: 9500, D Loss: -3.914715051651001, G Loss: -9.193463325500488\n",
      "Epoch: 10/50, Step: 10000, D Loss: -3.803218364715576, G Loss: -5.4726362228393555\n",
      "Epoch: 11/50, Step: 10500, D Loss: -3.6799380779266357, G Loss: -4.990134239196777\n",
      "Epoch: 11/50, Step: 11000, D Loss: -2.8258650302886963, G Loss: -6.088724136352539\n",
      "Epoch: 12/50, Step: 11500, D Loss: -2.8404955863952637, G Loss: -7.741921901702881\n",
      "Epoch: 12/50, Step: 12000, D Loss: -3.439532518386841, G Loss: -0.2079107165336609\n",
      "Epoch: 13/50, Step: 12500, D Loss: -3.0759501457214355, G Loss: -3.8485212326049805\n",
      "Epoch: 13/50, Step: 13000, D Loss: -3.5211479663848877, G Loss: -0.39581355452537537\n",
      "Epoch: 14/50, Step: 13500, D Loss: -2.2264626026153564, G Loss: -3.4813623428344727\n",
      "Epoch: 14/50, Step: 14000, D Loss: -2.447448253631592, G Loss: -7.541576385498047\n",
      "Epoch: 15/50, Step: 14500, D Loss: -2.386113166809082, G Loss: -4.689811706542969\n",
      "Epoch: 16/50, Step: 15000, D Loss: -3.155534505844116, G Loss: -8.664085388183594\n",
      "Epoch: 16/50, Step: 15500, D Loss: -2.6224143505096436, G Loss: 1.3822267055511475\n",
      "Epoch: 17/50, Step: 16000, D Loss: -3.2686221599578857, G Loss: 1.1641881465911865\n",
      "Epoch: 17/50, Step: 16500, D Loss: -2.511488676071167, G Loss: -4.31569242477417\n",
      "Epoch: 18/50, Step: 17000, D Loss: -2.323664665222168, G Loss: -7.968682289123535\n",
      "Epoch: 18/50, Step: 17500, D Loss: -2.712233543395996, G Loss: -5.017420768737793\n",
      "Epoch: 19/50, Step: 18000, D Loss: -2.2265477180480957, G Loss: -0.6633352637290955\n",
      "Epoch: 19/50, Step: 18500, D Loss: -2.052786111831665, G Loss: -8.980762481689453\n",
      "Epoch: 20/50, Step: 19000, D Loss: -2.2822625637054443, G Loss: -8.371345520019531\n",
      "Epoch: 20/50, Step: 19500, D Loss: -2.0346739292144775, G Loss: -5.704438209533691\n",
      "Epoch: 21/50, Step: 20000, D Loss: -1.9425594806671143, G Loss: -6.158945083618164\n",
      "Epoch: 21/50, Step: 20500, D Loss: -1.8346604108810425, G Loss: -6.76129150390625\n",
      "Epoch: 22/50, Step: 21000, D Loss: -1.5838919878005981, G Loss: -3.837240219116211\n",
      "Epoch: 22/50, Step: 21500, D Loss: -1.8366979360580444, G Loss: -1.3829818964004517\n",
      "Epoch: 23/50, Step: 22000, D Loss: -1.7080156803131104, G Loss: -6.069168567657471\n",
      "Epoch: 24/50, Step: 22500, D Loss: -2.1007423400878906, G Loss: -9.287784576416016\n",
      "Epoch: 24/50, Step: 23000, D Loss: -1.733026385307312, G Loss: -4.758201599121094\n",
      "Epoch: 25/50, Step: 23500, D Loss: -2.122978925704956, G Loss: -3.854278564453125\n",
      "Epoch: 25/50, Step: 24000, D Loss: -1.2089732885360718, G Loss: -4.343635559082031\n",
      "Epoch: 26/50, Step: 24500, D Loss: -1.7029880285263062, G Loss: -4.700730323791504\n",
      "Epoch: 26/50, Step: 25000, D Loss: -1.159062385559082, G Loss: -8.807985305786133\n",
      "Epoch: 27/50, Step: 25500, D Loss: -1.2818081378936768, G Loss: -5.57288122177124\n",
      "Epoch: 27/50, Step: 26000, D Loss: -1.1028286218643188, G Loss: -4.186102867126465\n",
      "Epoch: 28/50, Step: 26500, D Loss: -1.1051876544952393, G Loss: -0.958532452583313\n",
      "Epoch: 28/50, Step: 27000, D Loss: -1.4040178060531616, G Loss: -2.2421035766601562\n",
      "Epoch: 29/50, Step: 27500, D Loss: -1.3862742185592651, G Loss: -0.784112274646759\n",
      "Epoch: 29/50, Step: 28000, D Loss: -1.0255035161972046, G Loss: -6.899389266967773\n",
      "Epoch: 30/50, Step: 28500, D Loss: -1.1710888147354126, G Loss: -5.643136978149414\n",
      "Epoch: 30/50, Step: 29000, D Loss: -1.2006452083587646, G Loss: -2.9709839820861816\n",
      "Epoch: 31/50, Step: 29500, D Loss: -1.5284416675567627, G Loss: -4.902176856994629\n",
      "Epoch: 32/50, Step: 30000, D Loss: -0.8512096405029297, G Loss: -2.4139351844787598\n",
      "Epoch: 32/50, Step: 30500, D Loss: -1.0393633842468262, G Loss: -4.097910404205322\n",
      "Epoch: 33/50, Step: 31000, D Loss: -0.882887601852417, G Loss: 1.489929437637329\n",
      "Epoch: 33/50, Step: 31500, D Loss: -1.1883561611175537, G Loss: -3.380671739578247\n",
      "Epoch: 34/50, Step: 32000, D Loss: -1.1938151121139526, G Loss: 1.2561410665512085\n",
      "Epoch: 34/50, Step: 32500, D Loss: -1.3562498092651367, G Loss: -4.613578796386719\n",
      "Epoch: 35/50, Step: 33000, D Loss: -1.3277199268341064, G Loss: -0.5243163704872131\n",
      "Epoch: 35/50, Step: 33500, D Loss: -0.9779086709022522, G Loss: -4.448678016662598\n",
      "Epoch: 36/50, Step: 34000, D Loss: -0.8669332265853882, G Loss: -5.570426940917969\n",
      "Epoch: 36/50, Step: 34500, D Loss: -0.5758848190307617, G Loss: -2.786022424697876\n",
      "Epoch: 37/50, Step: 35000, D Loss: -0.9837555289268494, G Loss: -4.472448348999023\n",
      "Epoch: 37/50, Step: 35500, D Loss: -0.7650265097618103, G Loss: -5.31517219543457\n",
      "Epoch: 38/50, Step: 36000, D Loss: -1.2643911838531494, G Loss: -2.4497270584106445\n",
      "Epoch: 38/50, Step: 36500, D Loss: -1.1258745193481445, G Loss: -0.9633494019508362\n",
      "Epoch: 39/50, Step: 37000, D Loss: -0.6877334713935852, G Loss: -2.286830186843872\n",
      "Epoch: 40/50, Step: 37500, D Loss: -0.7125467658042908, G Loss: -2.928374767303467\n",
      "Epoch: 40/50, Step: 38000, D Loss: -1.084014892578125, G Loss: -3.0031416416168213\n",
      "Epoch: 41/50, Step: 38500, D Loss: -0.7037502527236938, G Loss: -1.9805595874786377\n",
      "Epoch: 41/50, Step: 39000, D Loss: -0.9223014712333679, G Loss: -3.971158504486084\n",
      "Epoch: 42/50, Step: 39500, D Loss: -0.5026755928993225, G Loss: -5.555987358093262\n",
      "Epoch: 42/50, Step: 40000, D Loss: -1.1474589109420776, G Loss: -5.670648574829102\n",
      "Epoch: 43/50, Step: 40500, D Loss: -0.7383836507797241, G Loss: -4.194655418395996\n",
      "Epoch: 43/50, Step: 41000, D Loss: -1.1405528783798218, G Loss: -5.927704334259033\n",
      "Epoch: 44/50, Step: 41500, D Loss: -0.807501494884491, G Loss: -3.6915783882141113\n",
      "Epoch: 44/50, Step: 42000, D Loss: -0.8019829392433167, G Loss: -3.4908132553100586\n",
      "Epoch: 45/50, Step: 42500, D Loss: -1.225110411643982, G Loss: -2.437776565551758\n",
      "Epoch: 45/50, Step: 43000, D Loss: -0.9028505682945251, G Loss: -6.611172199249268\n",
      "Epoch: 46/50, Step: 43500, D Loss: -0.925484836101532, G Loss: -3.2142438888549805\n",
      "Epoch: 46/50, Step: 44000, D Loss: -0.7895946502685547, G Loss: -2.345815420150757\n",
      "Epoch: 47/50, Step: 44500, D Loss: -0.720172107219696, G Loss: -5.039434432983398\n",
      "Epoch: 48/50, Step: 45000, D Loss: -0.6154714822769165, G Loss: -4.469676971435547\n",
      "Epoch: 48/50, Step: 45500, D Loss: -1.1894901990890503, G Loss: -3.4630775451660156\n",
      "Epoch: 49/50, Step: 46000, D Loss: -0.657228946685791, G Loss: -4.286595344543457\n",
      "Epoch: 49/50, Step: 46500, D Loss: -1.0294578075408936, G Loss: -2.8286654949188232\n"
     ]
    }
   ],
   "source": [
    "for epoch in range(max_epoch):\n",
    "    for idx, (images, labels) in enumerate(data_loader):\n",
    "        D.zero_grad()\n",
    "        ## Training Discriminator\n",
    "        # Real data\n",
    "        x = images.to(DEVICE)\n",
    "        y = labels.view(batch_size, 1)\n",
    "        y = to_onehot(y).to(DEVICE)\n",
    "        \n",
    "        # Sampling\n",
    "        z = torch.randn(batch_size, n_noise).to(DEVICE)\n",
    "        x_fake = G(z, y)\n",
    "                \n",
    "        # Gradient Penalty (e.g. gradients w.r.t x_penalty)\n",
    "        eps = torch.rand(batch_size, 1, 1, 1).to(DEVICE) # x shape: (64, 1, 28, 28)\n",
    "        x_penalty = eps*x + (1-eps)*x_fake\n",
    "        x_penalty = x_penalty.view(x_penalty.size(0), -1)\n",
    "        p_outputs = D(x_penalty, y)\n",
    "        xp_grad = autograd.grad(outputs=p_outputs, inputs=x_penalty, grad_outputs=D_labels,\n",
    "                                create_graph=True, retain_graph=True, only_inputs=True)\n",
    "        grad_penalty = p_coeff * torch.mean(torch.pow(torch.norm(xp_grad[0], 2, 1) - 1, 2))\n",
    "        \n",
    "        # Wasserstein loss\n",
    "        x_outputs = D(x, y)\n",
    "        z_outputs = D(x_fake, y)\n",
    "        D_x_loss = torch.mean(x_outputs)\n",
    "        D_z_loss = torch.mean(z_outputs)\n",
    "        D_loss = D_z_loss - D_x_loss + grad_penalty\n",
    "        \n",
    "        D_loss.backward()\n",
    "        D_opt.step()        \n",
    "        if step % n_critic == 0:\n",
    "            D.zero_grad()\n",
    "            G.zero_grad()\n",
    "            # Training Generator\n",
    "            z = torch.randn(batch_size, n_noise).to(DEVICE)\n",
    "            z_outputs = D(G(z, y), y)\n",
    "            G_loss = -torch.mean(z_outputs)\n",
    "\n",
    "            G_loss.backward()\n",
    "            G_opt.step()\n",
    "        \n",
    "        if step % 500 == 0:\n",
    "            print('Epoch: {}/{}, Step: {}, D Loss: {}, G Loss: {}'.format(epoch, max_epoch, step, D_loss.item(), G_loss.item()))\n",
    "        \n",
    "        if step % 1000 == 0:\n",
    "            G.eval()\n",
    "            img = get_sample_image(G, n_noise)\n",
    "            imsave('samples/{}_step{:05d}.jpg'.format(MODEL_NAME, step), img, cmap='gray')\n",
    "            G.train()\n",
    "        step += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Sample"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f23f053c0f0>"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f23f0638588>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# generation to image\n",
    "G.eval()\n",
    "imshow(get_sample_image(G, n_noise), cmap='gray')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def save_checkpoint(state, file_name='checkpoint.pth.tar'):\n",
    "    torch.save(state, file_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Saving params.\n",
    "# torch.save(D.state_dict(), 'D_c.pkl')\n",
    "# torch.save(G.state_dict(), 'G_c.pkl')\n",
    "save_checkpoint({'epoch': epoch + 1, 'state_dict':D.state_dict(), 'optimizer' : D_opt.state_dict()}, 'D_gp.pth.tar')\n",
    "save_checkpoint({'epoch': epoch + 1, 'state_dict':G.state_dict(), 'optimizer' : G_opt.state_dict()}, 'G_gp.pth.tar')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
